home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of MacTutor - S…e Code for Volumes 1 to 5
/
The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin
/
Source Code
/
#27 (Dec 87)
/
c daisy printer driver
/
PDEF0.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-09-29
|
10KB
|
398 lines
/*
* LightspeedC source for PDEF 0, routines to implement draft mode printing
* on a serial device.
* Earle R. Horton, September 19, 1987.
* All rights reserved.
*/
#include "prglobals.h"
#include <EventMgr.h>
pascal TPPrPort myPrOpenDoc();
pascal void myPrCloseDoc();
pascal void myPrOpenPage();
pascal void myPrClosePage();
pascal void myStdText();
pascal int myStdTextMeas();
void myClearPage();
Ptr allocate();
void free();
void bcopy();
DPstorage DrvrStorage();
void checkabort();
main(){
asm{
dc.w ILLEGAL ;; So I can find it...
jmp myPrOpenDoc
jmp myPrCloseDoc
jmp myPrOpenPage
jmp myPrClosePage
}
}
/*
* This function is supposed to return a pointer to a specialized GrafPort
* (a TPrPort) customized for printing. Due to the paucity of documentation
* on how to go about this, I do not know whether I am going about this in
* exactly the right way, but I sure hope so. I set portBits.bounds for the
* port to the empty Rect {0,0,0,0} and then install the standard QuickDraw
* routines as GrafProcs. In place of StdText, I put my own StdText routine.
* Hopefully, QuickDraw will keep track of the correct pen location for me,
* and call my routine whenever it is necessary to draw text. I just put
* the text in a big buffer for now, and then print it out when I get called
* to close the current page. This takes up some memory, but solves the
* problem of what to do when the application wants a reverse line feed.
* Other tasks:
* save a copy of the user print record for later use in formatting the
* output page
* save a copy of the user print record in the printer resource file
*/
pascal TPPrPort myPrOpenDoc(hPrint,pPrPort,pIOBuf)
THPrint hPrint;
TPPrPort pPrPort;
Ptr pIOBuf;
{
TPPrPort thisport;
pline thepage;
Handle us;
register DPstorage dsp;
THPrint savePrint;
PrParam *pb;
us = (Handle)(GetResource('PDEF',0));
asm{
move.l us,a0
HLock
}
/* Assign storage for printing port and page buffer. */
if((thepage = (pline)allocate((long)(NROWS*sizeof(line)))) == nil){
PrintErr = iMemFullErr;
return nil;
}
else if(pPrPort == nil){
if((thisport = (TPPrPort)
allocate((long)sizeof(TPrPort))) == nil){
free(thepage);
PrintErr = iMemFullErr;
return(nil);
}
thisport->fOurPtr = TRUE;
}
else {
thisport = pPrPort;
thisport->fOurPtr = FALSE;
}
/* Copy print record into private storage area. */
dsp = DrvrStorage();
pb = &dsp->prpb;
dsp->Print = **hPrint;
thisport->lGParam4 = (long)thepage;
dsp->Print.prJob.bJDocLoop = bDraftLoop;
OpenPort(thisport);
/* Fill out gProcs for this port. */
SetStdProcs(&thisport->gProcs);
thisport->gProcs.textProc = (QDPtr)myStdText;
thisport->gProcs.txMeasProc = (QDPtr)myStdTextMeas;
thisport->gPort.grafProcs = &thisport->gProcs;
/*
* Set up the port Rect in the proper coordinates, relative to the page
* and to the paper.
*/
thisport->gPort.device = dsp->Print.prInfo.iDev;
thisport->gPort.portRect = dsp->Print.prInfo.rPage;
thisport->gPort.portBits.bounds.top =
thisport->gPort.portBits.bounds.left =
thisport->gPort.portBits.bounds.bottom =
thisport->gPort.portBits.bounds.right = 0;
SetPort(thisport);
/* Offset the page (portRect) relative to the paper. */
PortSize
(dsp->Print.prInfo.rPage.right,dsp->Print.prInfo.rPage.bottom);
MovePortTo(- dsp->Print.rPaper.left, - dsp->Print.rPaper.top);
GrafDevice(dsp->Print.prInfo.iDev);
myClearPage(thepage);
pb->csCode = iPrDevCtl; /* Init the printer. */
pb->lParam1 = lPrReset; /* Driver code does the work. */
asm{
move.l pb,a0
PBControl
}
dsp->pagenum = 1;
if(dsp->Print.prJob.pIdleProc == nil)
dsp->Print.prJob.pIdleProc = (ProcPtr)checkabort;
savePrint = (THPrint)GetResource('PREC',1);
if(savePrint != nil){
LoadResource(savePrint);
**savePrint = dsp->Print;
ChangedResource(savePrint);
ReleaseResource(savePrint);
} /* Determine proper margins. */
dsp->nlines = (dsp->Print.rPaper.bottom - dsp->Print.rPaper.top)/
CHARHEIGHT;
return(thisport);
}
pascal void myPrCloseDoc(pPrPort)
TPPrPort pPrPort;
{
pline thepage;
Pfg settings;
free(pPrPort->lGParam4);
ClosePort(pPrPort);
if(pPrPort->fOurPtr) free(pPrPort);
}
/*
* This routine opens a new page. Actually, all it does is clear out the
* array of lines in preparation for more fun with QuickDraw. I suppose it
* could also send a reset command to the driver...
*/
pascal void myPrOpenPage(pPrPort,pPageFrame)
TPPrPort pPrPort;
TPRect pPageFrame;
{
register DPstorage dsp;
dsp = DrvrStorage();
if(pPageFrame != nil)
*pPageFrame = dsp->Print.prInfo.rPage;
SetPort(pPrPort);
myClearPage(pPrPort->lGParam4);
}
/*
* This is the routine which does the actual printing. QuickDraw calls
* which have called our StdText substitute routine have filled up a
* buffer with lines of text. Now, we just get the buffer and print it.
*/
pascal void myPrClosePage(pPrPort)
TPPrPort pPrPort;
{
register DPstorage dsp;
register pline theline;
register int i,iocount;
PrParam *pb;
dsp = DrvrStorage();
pb = &dsp->prpb;
if(dsp->pagenum < dsp->Print.prJob.iFstPage){
dsp->pagenum++;
return;
}
if(dsp->pagenum++ > dsp->Print.prJob.iLstPage){
PrintErr = iPrAbort;
if (dsp->preofstr[0] != '\0'){
pb->csCode = iPrIOCtl;
pb->lParam1 = (long)(&dsp->preofstr[1]);
pb->lParam2 = (long)dsp->preofstr[0];
asm{
move.l pb,a0
PBControl
}
}
return;
}
if(dsp->Print.prStl.feed != feedCut || waitnextpage()){
theline = (pline)pPrPort->lGParam4;
if (dsp->prtopstr[0] != '\0'){
pb->csCode = iPrIOCtl;
pb->lParam1 = (long)(&dsp->prtopstr[1]);
pb->lParam2 = (long)dsp->prtopstr[0];
asm{
move.l pb,a0
PBControl
}
}
for(i=0;dsp->nlines - i;i++){
(* dsp->Print.prJob.pIdleProc)();
if(PrintErr == iPrAbort)return;
if((theline+i)->dirty == DIRTY){
iocount = WIDTH;
while( (theline+i)->text[--iocount] == ' '){}
++iocount;
pb->csCode = iPrIOCtl;
pb->lParam1 =
(long)(&(theline+i)->text[0]);
pb->lParam2 = (long)iocount;
asm{
move.l pb,a0
PBControl
}
}
pb->csCode = iPrDevCtl;
if(i < dsp->nlines - 1)
pb->lParam1 = lPrLineFeed;
else pb->lParam1 = lPrPageEnd;
asm{
move.l pb,a0
PBControl
}
}
}
else PrintErr = iPrAbort;
}
/*
* All text drawing calls in the TPrPort get sent here. Find the current
* pen location and translate it to row and column of the page buffer,
* squirt the text into the buffer.
*/
pascal void myStdText(byteCount,textBuf,numer,denom)
int byteCount;
QDPtr textBuf;
Point numer,denom;
{
Point thepoint;
TPPrPort tp;
pline thepage;
int width;
int x,y;
GetPort(&tp);
if(tp->gPort.device == IDEV10) width = 7;
else if(tp->gPort.device == IDEV15) width = 5;
else width = 6;
thepage = (pline)tp->lGParam4;
GetPen(&thepoint);
/* (Local is page, Global is paper.) */
LocalToGlobal(&thepoint);
x = thepoint.h/width;
y = thepoint.v/CHARHEIGHT;
bcopy(textBuf,&((thepage+y)->text[x]),byteCount);
(thepage+y)->dirty = DIRTY;
Move(width*byteCount,0);
}
pascal int myStdTextMeas(byteCount,textBuf,numer,denom,info)
int byteCount;
QDPtr textBuf;
Point *numer,*denom;
FontInfo *info;
{
TPPrPort tp;
GetPort(&tp);
if(tp->gPort.device == IDEV10)info->widMax = 7;
else if(tp->gPort.device == IDEV15)info->widMax = 5;
else info->widMax = 6;
info->ascent = 9;
info->descent = 2;
info->leading = 0;
numer->v = denom->v = 1;
denom->h = 6;
numer->h = info->widMax;
return (info->widMax * byteCount);
}
void myClearPage(theline)
pline theline;
{
int count;
unsigned char *ch;
count = NROWS;
clear:
theline->dirty = ~DIRTY;
ch = &theline->text[0];
asm{
move.l ch,a0
move.w #((WIDTH/4)-1),d0
move.l #0x20202020,d1
loop:
move.l d1,(a0)+
dbra d0,@loop
}
if(--count){
theline++;
goto clear;
}
}
Ptr allocate(size)
long size;
{
asm{
move.l size,d0
NewPtr
move.l a0,d0 ;; LightspeedC returns function
} /* value in d0. */
}
void free(ptr)
Ptr ptr;
{
asm{
move.l ptr,a0
DisposPtr
}
}
/*
* A UNIXism. Want to make something of it?
*/
void bcopy(src,dst,count)
unsigned char *src,*dst;
int count;
{
asm{
move.l src,a0
move.l dst,a1
clr.l d0
move.w count,d0
BlockMove
}
}
#define UTableBase 284
/*
* This function returns a pointer to the printer driver's private
* storage. We don't need to lock the Handle, since it is always locked
* when the driver is open.
*/
DPstorage DrvrStorage()
{
DCtlHandle ourDCtlEntry;
DHstorage ourdCtlStorage;
asm{
move #2,d0
asl.l #2,d0 ;; d0 = 8L
move.l UTableBase,a0 ;; a0 -> base of unit table
adda d0,a0 ;; a0 -> second entry
move.l (a0),ourDCtlEntry ;; handle to DCtlEntry[2]
}
ourdCtlStorage = (DHstorage)(*ourDCtlEntry)->dCtlStorage;
return(*ourdCtlStorage);
}
/*
* Abort printing if command '.' pressed.
*/
void checkabort()
{
EventRecord myevent;
int c;
if (GetNextEvent(keyDownMask, &myevent)){
if(LoWord(myevent.message & charCodeMask) == '.' &&
(myevent.modifiers & cmdKey) ){
PrintErr = iPrAbort;
}
}
}
/*
* Modal dialog box: "Insert next sheet."
*/
waitnextpage()
{
DialogPtr sheetdialog;
WindowPtr tempport;
int itemhit,donetype;
Handle doneitem;
Rect donebox;
if((sheetdialog = GetNewDialog(SHEETDIALOG, 0L,(WindowPtr) -1)) == nil)
return FALSE;
InitCursor();
GetDItem(sheetdialog,DONEITEM,&donetype,&doneitem,&donebox);
GetPort(&tempport);
SetPort(sheetdialog);
PenSize(3,3);
InsetRect(&donebox,-4,-4);
FrameRoundRect(&donebox,16,16);
ModalDialog(0L,&itemhit);
DisposDialog(sheetdialog);
SetPort(tempport);
if(itemhit == STOPITEM) return FALSE;
return TRUE;
}